/**
  * @file point_list.h
  * @author Thibault Merle et Guillaume Poussel
  */
#ifndef POINTLIST_H
#define POINTLIST_H

#include <list>
#include "base/Point.h"

/**
  * @brief Classe représentant une liste de points
  *
  * Elle contient des méthodes utiles aux opérations géométriques sur les
  * ensembles de points et permet l'abstraction du type \p std\::list sous-jacent.
  */
class point_list : public std::list<Point*> {
public:
    point_list() : std::list<Point*>() {};
    point_list(point_list::iterator deb, point_list::iterator fin)
        : std::list<Point*>(deb, fin) {};

    /**
      * Génère une liste de points générés aléatoirement
      * @param nb Nombre de points de la liste
      * @param min Valeur minimum pour les coordonnées
      * @param max Valeur maximum pour les coordonnées
      * @return Liste de points générés aléatoirement
      */
    static point_list get_random_points(const unsigned long int nb, const int min, const int max);

    /**
      * Retire la tête de liste.
      * @warning Cette méthode doit être utilisée après avoir mélangé
      * la liste à l'aide de #shuffle.
      * @return Le point que l'on vient de retirer
      */
    Point* pick_point();

    /**
      * Mélange aléatoirement une liste
      */
    void shuffle();

    /**
      * Récupère le barycentre de l'ensemble de points
      * @return Le point situé au centre du polygone
      */
    Point* get_centroid() const;

    /**
      * Récupère le losange constitué des points \e extremums en abscisse
      * et en ordonnées de cet ensemble de points.
      */
    point_list get_diamond() const;

    /**
      * Détermine si un point appartient ou non à cet ensemble de points.
      * @remarks Cette méthode est valide à la seule condition que le polygone
      * soit simple (donc convexe ou non).
      * @param pt Point à tester
      * @return \p true si le point est à l'intérieur, \p false sinon.
      */
    bool contains(const Point* pt) const;

    /** \defgroup list_iterators Opérations avec les itérateurs */
    /* @{ */
    /**
      * Récupère le prochain point parmi cet ensemble de points. Si la fin de la
      * liste est atteinte, on retourne au début.
      * @param it Itérateur sur le point en cours
      * @return Point suivant \p it dans cette liste
      */
    point_list::iterator next_point(point_list::iterator it);
    /**
      * Récupère le point précédent parmi cet ensemble de points.
      * Si le début de la liste est atteint, on retourne à la fin.
      * @param it Itérateur sur le point en cours
      * @return Point précédant \p it dans cette liste
      */
    point_list::iterator prev_point(point_list::iterator it);
    /**
      * Avance un itérateur d'une case dans cette liste (et retourne au début
      * si besoin).
      * @param it Itérateur à déplacer d'une case en avant
      */
    void advance(point_list::iterator& it);
    /**
      * Recule un itérateur d'une case dans cette liste (et retourne à la fin
      * si besoin).
      * @param it Itérateur à déplacer d'une case en arrière
      */
    void move_back(point_list::iterator& it);
    /* @} */

    /**
      * Récupère le \c n-ième élément de la liste.
      *
      * L'implémentation de \p std\::list correspond à des listes doublement
      * chaînées et ne contient donc pas d'opérateur d'indexation. Pour faciliter
      * la lecture du code, cet opérateur est ici surchargé.
      * @warning Cette méthode n'est pas exécutée en temps constant, mais plutôt
      * en \f$O(n)\f$.
      */
    Point* operator[](const int);
    /**
      * @copydoc #operator[]
      */
    Point* operator[](const int) const;
};

#endif // POINTLIST_H
